package com.ltf.servlet;


import com.ltf.springframework.annotation.Autowired;
import com.ltf.springframework.annotation.Controller;
import com.ltf.springframework.annotation.Service;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class ServletDispachar extends HttpServlet {

    private Properties configProperties = new Properties();

    private List<String> beanNames = new ArrayList<>();

    private Map<String,Object> beanMap = new ConcurrentHashMap<>();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("开始调用doPost方法");
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        // 定位
        doLoadConfig(config.getInitParameter("contextConfigLocation"));
        // 加载
        doScaner(configProperties.getProperty("package"));
        // 注册
        doRegister();
        // 依赖注入
        doAutowired();

       /* DemoController demoController = (DemoController) beanMap.get("demoController");
        demoController.testDemo();*/

    }

    private void doAutowired() {
        Set<Map.Entry<String, Object>> entries = beanMap.entrySet();
        for (Map.Entry<String, Object> entry : entries) {
            Object o = entry.getValue();
            Field[] declaredFields = o.getClass().getDeclaredFields();
            for (Field declaredField : declaredFields) {
                if(declaredField.isAnnotationPresent(Autowired.class)){
                    String value = declaredField.getAnnotation(Autowired.class).value();
                    if("".equals(value)){
                        declaredField.setAccessible(true);
                        try {
                            declaredField.set(entry.getValue(),beanMap.get(declaredField.getType().getName()));
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

        }
    }

    private void doRegister() {
        if (beanNames.isEmpty()){
            return;
        }
        try {
            for (String beanName : beanNames) {
                Class<?> clazz = Class.forName(beanName);
                if(clazz.isAnnotationPresent(Controller.class)){
                    beanMap.put(firstToLower(clazz.getSimpleName()),clazz.newInstance());
                }else if (clazz.isAnnotationPresent(Service.class)){
                    String name = clazz.getAnnotation(Service.class).value();
                    Object o = clazz.newInstance();
                    if("".equals(name.trim())){
                        beanMap.put(firstToLower(clazz.getSimpleName()),o);
                    }
                    Class<?>[] interfaces = clazz.getInterfaces();
                    for (Class<?> anInterface : interfaces) {
                        beanMap.put(anInterface.getName(),o);
                    }

                }

            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private void doScaner(String packageName) {
        URL url = this.getClass().getClassLoader().getResource("/" + packageName.replaceAll("\\.", "/"));
        File file = new File(url.getFile());
        for (File f : file.listFiles()) {
            if (f.isDirectory()){
                doScaner(packageName+"."+f.getName());
            }else {
                beanNames.add(packageName+"."+f.getName().replace(".class",""));
            }
        }


    }

    private String firstToLower(String beanName){
        char[] chars = beanName.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }

    private void doLoadConfig(String contextConfigLocation) {
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation.replace("classpath:", ""));
        try {
            configProperties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


}
